package mdc

import (
	"go.uber.org/zap"
	"sync"
	"wzgames/internal/client"
	"wzgames/internal/constant"
	"wzgames/internal/model/dwp"
	"wzgames/internal/model/gamep"
	"wzgames/internal/model/login"
	"wzgames/internal/response"
	"wzgames/internal/services/games"
	"wzgames/pkg/actor/actor"
	"wzgames/pkg/actor/actorservice"
	"wzgames/pkg/logger"
	"wzgames/pkg/server/ws"
)

type HallAgent struct {
	agtId  int64
	agtKey string

	players map[uint64]*Player // 代理下的玩家列表

	mu sync.RWMutex
}

func NewHallAgent(agtId int64, agtKey string) *HallAgent {
	a := &HallAgent{
		agtId:   agtId,
		agtKey:  agtKey,
		players: make(map[uint64]*Player),
	}

	return a
}

func (ha *HallAgent) AgtID() int64 {
	return ha.agtId
}

func (ha *HallAgent) AgtKey() string {
	return ha.agtKey
}

func (ha *HallAgent) GetPlayer(uid uint64) *Player {
	ha.mu.RLock()
	p, ok := ha.players[uid]
	ha.mu.RUnlock()
	if ok {
		return p
	}

	return nil
}

// LoginGame 玩家登录游戏服
func (ha *HallAgent) LoginGame(sess ws.ISession, data *login.LoginGame) {
	// 优先获取对应币种方案
	gameCurr, code := client.GetGameCurrency(data.Reply.GcId)
	if code != 0 {
		receiver.GenLoginErr(sess, code)
		return
	}
	// 游戏实例获取
	inst := instMgr.GetInst(data.GameInstId)
	if inst == nil || gameCurr == nil || gameCurr.GcID == 0 {
		logger.Errorf("LoginGame gcid %d inst id %d inst %#v gameCurr %#v ", data.Reply.GcId, data.GameInstId, inst, gameCurr)
		receiver.GenLoginErr(sess, response.ErrUnAvailable)
		return
	}
	// 初始化新的游戏状态记录
	gtb := ha.genTable(sess, data, inst)
	if gtb == nil {
		return
	}
	gtb.GameCurr = gameCurr
	// 判断玩家Actor是否已经创建，有则登录游戏实例
	player := ha.GetPlayer(data.Reply.UserCache.Uid)
	if player != nil {
		sess.SetLink(player.Pid(), data.GameInstId)
		actorservice.Send(player.Pid(), gtb)
		return
	}
	ha.mu.Lock()
	defer ha.mu.Unlock()
	if p, ok := ha.players[data.Reply.UserCache.Uid]; ok {
		sess.SetLink(p.Pid(), data.GameInstId)
		actorservice.Send(p.Pid(), gtb)
		return
	}
	player = NewPlayer(data.Reply.UserCache, ha)
	ha.players[data.Reply.UserCache.Uid] = player
	sess.SetLink(player.Pid(), data.GameInstId)
	actorservice.Send(player.Pid(), gtb)
	return
}

func (ha *HallAgent) genTable(sess ws.ISession, data *login.LoginGame, inst games.IGameService) *games.GameTable {
	// 新的游戏状态器
	marker, err := games.NewMarker(inst.GetGameId())
	if err != nil {
		logger.Error("[MDC] gen game table fail on new marker", zap.Int64("InstID", inst.GameInstId()), zap.Error(err))
		receiver.GenLoginErr(sess, response.ErrInternal)
		return nil
	}
	gtb := &games.GameTable{
		Sess: sess,
		Seat: gamep.SeatInfo{
			SessID:     data.SessID,          // WebSocket sessionID
			GcId:       data.Reply.GcId,      // 币种方案ID
			Guest:      data.Reply.Guest,     // 是否游客
			CurrId:     data.Reply.CurrId,    // 币种ID
			Currency:   data.Currency,        // 币种Code
			Precision:  data.Reply.Precision, // 币种精度
			Lang:       data.Lang,            // 登录的客户端语言
			BToken:     data.Reply.BToken,
			WalletType: data.Reply.WalletType, // 钱包类型
		},
		Inst:   inst,
		Marker: marker,
	}
	return gtb
}

func (ha *HallAgent) PlayerPid(uid uint64) *actor.PID {
	player := ha.GetPlayer(uid)
	if player != nil {
		return player.Pid()
	}

	return nil
}

// CheckPlayerActive 检测该代理下的玩家的活跃情况
func (ha *HallAgent) CheckPlayerActive() {
	ha.mu.RLock()
	defer ha.mu.RUnlock()
	for _, p := range ha.players {
		actorservice.Send(p.Pid(), constant.ActiveCheck{})
	}
}

// RemovePlayer 移除某个玩家缓存
func (ha *HallAgent) RemovePlayer(uid uint64) {
	p := ha.GetPlayer(uid)
	if p != nil {
		ha.mu.Lock()
		delete(ha.players, uid)
		ha.mu.Unlock()
	}
}

func (ha *HallAgent) CheckKickCheck(req *login.LoginKickCheck) {
	player := ha.GetPlayer(req.Uid)
	if player != nil {
		actorservice.Send(player.Pid(), req)
	}
}

func (ha *HallAgent) CheckPlayerBalanceChange(req *dwp.BalanceChange) {
	player := ha.GetPlayer(req.Uid)
	if player != nil {
		actorservice.Send(player.Pid(), req)
	}
}
